﻿using UnityEngine;
using System;
using System.Collections;
using jp.nyatla.nyartoolkit.cs.markersystem;
using jp.nyatla.nyartoolkit.cs.core;
using NyARUnityUtils;
using System.IO;

namespace edu.wpi.cs.Project1
{
    /// <summary>
    /// The possible game phases.
    /// </summary>
    public enum GamePhase
    {
        Adjusting,
        Playing
    }

    /// <summary>
    /// AR camera behaviour.
    /// This sample shows simpleLite demo.
    /// 1.Connect webcam to your computer.
    /// 2.Start sample program
    /// 3.Take a "HIRO" marker and "KANJI" on capture image
    ///
    /// </summary>
    public class ARPhysicsBehaviour : MonoBehaviour
    {
        /// <summary>
        /// The AR marker system.
        /// </summary>
        private NyARUnityMarkerSystem markerSystem;

        /// <summary>
        /// The web cam sensor system.
        /// </summary>
        private NyARUnityWebCam webCamSensor;

        /// <summary>
        /// The background panels marker ID.
        /// </summary>
        private GameObject backgroundPanel;

        /// <summary>
        /// The emitter which emits balls.
        /// </summary>
        private TrackedGameObject emitter;

        /// <summary>
        /// The goal which must be reached by the ball.
        /// </summary>
        private TrackedGameObject goal;

        /// <summary>
        /// The simple collider.
        /// </summary>
        private TrackedGameObject simpleCollider;

        /// <summary>
        /// The ball game object.
        /// </summary>
        private GameObject ballObject;

        /// <summary>
        /// The current game phase.
        /// </summary>
        private GamePhase gamePhase;

        /// <summary>
        /// The adjustent phase timer
        /// </summary>
        private float adjustTimer;

        /// <summary>
        /// The timer GUI text.
        /// </summary>
        private GUIText timerText;

        /// <summary>
        /// The player score.
        /// </summary>
        private int score;

        /// <summary>
        /// The score GUI text.
        /// </summary>
        private GUIText scoreText;

        /// <summary>
        /// The speed of the next ball.
        /// </summary>
        private int nextSpeed;

        /// <summary>
        /// The score GUI text.
        /// </summary>
        private GUIText nextSpeedText;

        /// <summary>
        /// Sets up the scene and the AR system.
        /// </summary>
        void Awake()
        {
            // setup unity webcam
            WebCamDevice[] devices = WebCamTexture.devices;
            WebCamTexture webCamTexture;

            if (devices.Length > 0)
            {
                webCamTexture = new WebCamTexture(320, 240, 15);
                this.webCamSensor = new NyARUnityWebCam(webCamTexture);

                NyARMarkerSystemConfig config = new NyARMarkerSystemConfig(
                    webCamTexture.requestedWidth,
                    webCamTexture.requestedHeight);
                this.markerSystem = new NyARUnityMarkerSystem(config);

                // created trackers
                this.emitter = new TrackedGameObject(this.markerSystem, "patt_hiro", true);
                this.goal = new TrackedGameObject(this.markerSystem, "patt_kanji", true);
                this.simpleCollider = new TrackedGameObject(this.markerSystem, "./Assets/Data/patt.ben");

                // setup background
                this.backgroundPanel = GameObject.Find("Plane");
                this.backgroundPanel.renderer.material.mainTexture = webCamTexture;
                this.markerSystem.setARBackgroundTransform(this.backgroundPanel.transform);

                // setup camera projection
                this.markerSystem.setARCameraProjection(this.camera);
            }
            else
            {
                Debug.LogError("No Webcam.");
            }
        }

        /// <summary>
        /// Starts the web cam.
        /// </summary>
        void Start()
        {
            //start sensor
            this.webCamSensor.start();

            // initialze trackers with associated game objects
            this.emitter.Initialize("EmitterMarker", "Emitter");
            this.goal.Initialize("GoalMarker", "Goal");
            this.simpleCollider.Initialize("SimpleColliderMarker", "SimpleCollider");

            // start game
            this.StartRound();

            // Text UI
            timerText = GameObject.Find("TimerText").GetComponent<GUIText>();
            scoreText = GameObject.Find("ScoreText").GetComponent<GUIText>();
            nextSpeedText = GameObject.Find("NextSpeedText").GetComponent<GUIText>();
        }

        /// <summary>
        /// Updates the AR scene.
        /// </summary>
        void Update()
        {
            // update sensor system
            this.webCamSensor.update();
            // update marker system by the web cam sensor
            this.markerSystem.update(this.webCamSensor);


            if (gamePhase == GamePhase.Adjusting)
            {
                adjustTimer -= Time.deltaTime;
                adjustTimer = Math.Max(adjustTimer, 0.0f);

                // time UI
                timerText.text = string.Format("{0:00}:{1:00}", (int)adjustTimer, (int)((adjustTimer - (int)adjustTimer) * 60));

                if (adjustTimer == 0.0f)
                {
                    gamePhase = GamePhase.Playing;

                    // create ball
                    this.ballObject = CreateBall("Ball",
                                this.emitter.MarkerGameObject.transform.position,
                                this.emitter.MarkerGameObject.transform.rotation);
                    Utility.TranslateToXYLayer(ballObject, GameConfig.POSITION_Z);

                    // give the ball the appropriate impuls
                    ballObject.rigidbody.AddForce(-this.emitter.MarkerGameObject.transform.up.normalized * 200,
                        ForceMode.Impulse);
                }
                else
                {
                    // update tracked objects
                    this.emitter.Update();
                    this.goal.Update();
                    this.simpleCollider.Update();
                }
            }
            else if (gamePhase == GamePhase.Playing)
            {
                // time UI
                timerText.text = "PLAYING";

                // no translation of virtual objects to markers, the last recognized position
                // of all virtual objects should be keept until the game is ready. So the user is not
                // able to interact with virtual objects during game play
            }

            this.scoreText.text = string.Format("Score: {0:0000}", score);

            this.nextSpeedText.text = string.Format("Next speed: {0}", nextSpeed);
        }

        /// <summary>
        /// Starts a new game.
        /// </summary>
        public void StartRound()
        {
            gamePhase = GamePhase.Adjusting;

            adjustTimer = GameConfig.MARKER_ADJUST_TIME;

            nextSpeed = UnityEngine.Random.Range(GameConfig.MIN_BALL_IMPULS, GameConfig.MAX_BALL_IMPULS);
        }

        /// <summary>
        /// Adds player score.
        /// </summary>
        /// <param name="value">The value to add.</param>
        public void AddScore(int value)
        {
            this.score += value;
        }

        /// <summary>
        /// Crates a new ball.
        /// </summary>
        /// <param name="name">The name of the ball</param>
        /// <param name="position">The position of the ball</param>
        /// <param name="rotation">The rotation of the ball.</param>
        /// <returns>The ball object</returns>
        private GameObject CreateBall(string name, Vector3 position, Quaternion rotation)
        {
            GameObject ballPrefab = Resources.Load("BallPrefab") as GameObject;
            GameObject ball = Instantiate(ballPrefab, position, rotation) as GameObject;
            ball.name = name;
            return ball;
        }
    }
}
